package org.sunshine.mamadu;

import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;

public class XmlUtils {

    private static DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();


    public static byte[] getDocumentAsByteArray(Document document) throws Exception {
        ByteArrayOutputStream outputStream = null;
        try {
            outputStream = new ByteArrayOutputStream();
            Transformer transformer = getTransformer();
            Source source = new DOMSource(document);
            StreamResult result = new StreamResult(outputStream);
            transformer.transform(source, result);


            return outputStream.toByteArray();
        }
        finally {
            if (outputStream != null) {
                outputStream.close();
            }
        }
    }

    private static Transformer getTransformer() throws TransformerConfigurationException {
        Transformer transformer = TransformerFactoryImpl.newInstance().newTransformer();
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
        transformer.setOutputProperty(OutputKeys.METHOD, "xml");
        transformer.setOutputProperty(OutputKeys.STANDALONE, "yes");
        transformer.setOutputProperty(OutputKeys.MEDIA_TYPE, "text/xml");
        return transformer;
    }

    public static Document readDOMFromFile(String path) throws IOException, SAXException, ParserConfigurationException {
        DocumentBuilder builder = factory.newDocumentBuilder();
        return builder.parse(new File(path));
    }


    public static Document buildDOM(List<Advertisement> list) throws ParserConfigurationException {
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document document = builder.newDocument();
        Element root = document.createElement("mamadu");
        document.appendChild(root);
        for (int i=0; i < list.size(); i++){
            Advertisement advertisement = list.get(i);
            Element item = document.createElement("ad");
            item.setAttribute("id", String.valueOf(i));
            root.appendChild(item);

            Element name = document.createElement("name");
            name.appendChild(document.createTextNode(advertisement.getName()));
            item.appendChild(name);

            Element email = document.createElement("email");
            email.appendChild(document.createTextNode(advertisement.getEmail()));
            item.appendChild(email);

            Element phone = document.createElement("phone");
            phone.appendChild(document.createTextNode(advertisement.getPhone()));
            item.appendChild(phone);

            Element date = document.createElement("date");
            date.appendChild(document.createTextNode(advertisement.getDate()));
            item.appendChild(date);

            Element content = document.createElement("content");
            String contentData = advertisement.getContent();
            content.appendChild(document.createTextNode(contentData));
            item.appendChild(content);



        }
        return document;
    }


    public static void saveDomToFile(Document document, String path) throws Exception {
        FileOutputStream outputStream = new FileOutputStream(path, false);
        Transformer transformer = getTransformer();
        Source source = new DOMSource(document);
        StreamResult result = new StreamResult(outputStream);
        transformer.transform(source, result);
        outputStream.flush();
        outputStream.close();
    }


    public static String escape(String input){
        return input.replaceAll("[<>&]", "");
    }

    public static Node getNextSiblingElement(Node start){
        Node nextSibling = start.getNextSibling();
        if (nextSibling == null ) return null;
        if (nextSibling.getNodeType() == Node.ELEMENT_NODE) return nextSibling;
        return getNextSiblingElement(nextSibling);
    }

    public static List<Advertisement> getAdvertisementsFromFile(String filepath) throws IOException, ParserConfigurationException, SAXException {
        Document fromFile = null;
        try {
            fromFile = XmlUtils.readDOMFromFile(filepath);
        } catch (FileNotFoundException e) {
            return new ArrayList<Advertisement>();
        }
        return XmlUtils.getAdvertisementsFromDocument(fromFile);
    }
    
    public static List<Advertisement> getAdvertisementsFromDocument(Document doc){
        Element root = doc.getDocumentElement();
        Node adNode = root.getFirstChild();
        if (adNode.getNodeType() != Node.ELEMENT_NODE) adNode = getNextSiblingElement(adNode);
        ArrayList<Advertisement> advertisements = new ArrayList<Advertisement>();

        while(adNode != null){
            Advertisement advertisement = new Advertisement();

            String id = adNode.getAttributes().getNamedItem("id").getTextContent();
            advertisement.setId(Integer.parseInt(id));

            Node nameNode = adNode.getFirstChild();
            if (nameNode.getNodeType()!= Node.ELEMENT_NODE){
                nameNode = XmlUtils.getNextSiblingElement(nameNode);
            }
            Assert.assertTrue("name".equalsIgnoreCase(nameNode.getNodeName()));
            advertisement.setName(nameNode.getTextContent());

            Node emailNode = XmlUtils.getNextSiblingElement(nameNode);
            Assert.assertTrue("email".equalsIgnoreCase(emailNode.getNodeName()));
            advertisement.setEmail(emailNode.getTextContent());

            Node phoneNode = XmlUtils.getNextSiblingElement(emailNode);
            Assert.assertTrue("phone".equalsIgnoreCase(phoneNode.getNodeName()));
            advertisement.setPhone(phoneNode.getTextContent());

            Node dateNode = XmlUtils.getNextSiblingElement(phoneNode);
            Assert.assertTrue("date".equalsIgnoreCase(dateNode.getNodeName()));
            advertisement.setDate(dateNode.getTextContent());

            Node contentNode = XmlUtils.getNextSiblingElement(dateNode);
            Assert.assertTrue("content".equalsIgnoreCase(contentNode.getNodeName()));
            advertisement.setContent(contentNode.getTextContent());

            advertisements.add(advertisement);

            adNode = getNextSiblingElement(adNode);
        }

        return advertisements;
    }
}
